{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Optical Flow example\n",
    "This notebook presents how to use Dali to calculate optical flow for given sequence of frames."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's start with some handy imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "from __future__ import division\n",
    "import os.path\n",
    "import numpy as np\n",
    "\n",
    "from nvidia.dali.pipeline import Pipeline\n",
    "import nvidia.dali.ops as ops\n",
    "\n",
    "from matplotlib import pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Setting metaparameters.  \n",
    "As an example we use [Sintel trailer](https://durian.blender.org/), included in [DALI_extra](https://github.com/NVIDIA/DALI_extra) repository. Feel free to verify against your own video data.\n",
    "\n",
    "`DALI_EXTRA_PATH` environment variable should point to the place where data from [DALI extra repository](https://github.com/NVIDIA/DALI_extra) is downloaded. Please make sure that the proper release tag is checked out."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "batch_size = 1\n",
    "sequence_length = 10\n",
    "dali_extra_path = os.environ['DALI_EXTRA_PATH']\n",
    "video_filename = dali_extra_path + \"/db/optical_flow/sintel_trailer/sintel_trailer_short.mp4\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Functions used for Optical flow visualization.  \n",
    "The code comes from [Tomrunia's GitHub](https://github.com/tomrunia/OpticalFlow_Visualization \"OpticalFlow_Visualization\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_colorwheel():\n",
    "    '''\n",
    "    Generates a color wheel for optical flow visualization as presented in:\n",
    "        Baker et al. \"A Database and Evaluation Methodology for Optical Flow\" (ICCV, 2007)\n",
    "        URL: http://vision.middlebury.edu/flow/flowEval-iccv07.pdf\n",
    "    According to the C++ source code of Daniel Scharstein\n",
    "    According to the Matlab source code of Deqing Sun\n",
    "    '''\n",
    "\n",
    "    RY = 15\n",
    "    YG = 6\n",
    "    GC = 4\n",
    "    CB = 11\n",
    "    BM = 13\n",
    "    MR = 6\n",
    "\n",
    "    ncols = RY + YG + GC + CB + BM + MR\n",
    "    colorwheel = np.zeros((ncols, 3))\n",
    "    col = 0\n",
    "\n",
    "    # RY\n",
    "    colorwheel[0:RY, 0] = 255\n",
    "    colorwheel[0:RY, 1] = np.floor(255 * np.arange(0, RY) / RY)\n",
    "    col = col + RY\n",
    "    # YG\n",
    "    colorwheel[col:col + YG, 0] = 255 - np.floor(255 * np.arange(0, YG) / YG)\n",
    "    colorwheel[col:col + YG, 1] = 255\n",
    "    col = col + YG\n",
    "    # GC\n",
    "    colorwheel[col:col + GC, 1] = 255\n",
    "    colorwheel[col:col + GC, 2] = np.floor(255 * np.arange(0, GC) / GC)\n",
    "    col = col + GC\n",
    "    # CB\n",
    "    colorwheel[col:col + CB, 1] = 255 - np.floor(255 * np.arange(CB) / CB)\n",
    "    colorwheel[col:col + CB, 2] = 255\n",
    "    col = col + CB\n",
    "    # BM\n",
    "    colorwheel[col:col + BM, 2] = 255\n",
    "    colorwheel[col:col + BM, 0] = np.floor(255 * np.arange(0, BM) / BM)\n",
    "    col = col + BM\n",
    "    # MR\n",
    "    colorwheel[col:col + MR, 2] = 255 - np.floor(255 * np.arange(MR) / MR)\n",
    "    colorwheel[col:col + MR, 0] = 255\n",
    "    return colorwheel\n",
    "\n",
    "\n",
    "def flow_compute_color(u, v, convert_to_bgr=False):\n",
    "    '''\n",
    "    Applies the flow color wheel to (possibly clipped) flow components u and v.\n",
    "    According to the C++ source code of Daniel Scharstein\n",
    "    According to the Matlab source code of Deqing Sun\n",
    "    :param u: np.ndarray, input horizontal flow\n",
    "    :param v: np.ndarray, input vertical flow\n",
    "    :param convert_to_bgr: bool, whether to change ordering and output BGR instead of RGB\n",
    "    :return:\n",
    "    '''\n",
    "\n",
    "    flow_image = np.zeros((u.shape[0], u.shape[1], 3), np.uint8)\n",
    "\n",
    "    colorwheel = make_colorwheel()  # shape [55x3]\n",
    "    ncols = colorwheel.shape[0]\n",
    "\n",
    "    rad = np.sqrt(np.square(u) + np.square(v))\n",
    "    a = np.arctan2(-v, -u) / np.pi\n",
    "\n",
    "    fk = (a + 1) / 2 * (ncols - 1) + 1\n",
    "    k0 = np.floor(fk).astype(np.int32)\n",
    "    k1 = k0 + 1\n",
    "    k1[k1 == ncols] = 1\n",
    "    f = fk - k0\n",
    "\n",
    "    for i in range(colorwheel.shape[1]):\n",
    "        tmp = colorwheel[:, i]\n",
    "        col0 = tmp[k0] / 255.0\n",
    "        col1 = tmp[k1] / 255.0\n",
    "        col = (1 - f) * col0 + f * col1\n",
    "\n",
    "        idx = (rad <= 1)\n",
    "        col[idx] = 1 - rad[idx] * (1 - col[idx])\n",
    "        col[~idx] = col[~idx] * 0.75  # out of range?\n",
    "\n",
    "        # Note the 2-i => BGR instead of RGB\n",
    "        ch_idx = 2 - i if convert_to_bgr else i\n",
    "        flow_image[:, :, ch_idx] = np.floor(255 * col)\n",
    "\n",
    "    return flow_image\n",
    "\n",
    "\n",
    "def flow_to_color(flow_uv, clip_flow=None, convert_to_bgr=False):\n",
    "    '''\n",
    "    Expects a two dimensional flow image of shape [H,W,2]\n",
    "    According to the C++ source code of Daniel Scharstein\n",
    "    According to the Matlab source code of Deqing Sun\n",
    "    :param flow_uv: np.ndarray of shape [H,W,2]\n",
    "    :param clip_flow: float, maximum clipping value for flow\n",
    "    :return:\n",
    "    '''\n",
    "\n",
    "    assert flow_uv.ndim == 3, 'input flow must have three dimensions'\n",
    "    assert flow_uv.shape[2] == 2, 'input flow must have shape [H,W,2]'\n",
    "\n",
    "    if clip_flow is not None:\n",
    "        flow_uv = np.clip(flow_uv, 0, clip_flow)\n",
    "\n",
    "    u = flow_uv[:, :, 0]\n",
    "    v = flow_uv[:, :, 1]\n",
    "\n",
    "    rad = np.sqrt(np.square(u) + np.square(v))\n",
    "    rad_max = np.max(rad)\n",
    "\n",
    "    epsilon = 1e-5\n",
    "    u = u / (rad_max + epsilon)\n",
    "    v = v / (rad_max + epsilon)\n",
    "\n",
    "    return flow_compute_color(u, v, convert_to_bgr)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using Dali\n",
    "### Define the Pipeline.  \n",
    "For advanced usage, refer to SequenceReader and VideoReader docs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class OFPipeline(Pipeline):\n",
    "    def __init__(self, batch_size, num_threads, device_id):\n",
    "        super(OFPipeline, self).__init__(batch_size, num_threads, device_id, seed=16)\n",
    "\n",
    "        self.input = ops.VideoReader(device=\"gpu\", filenames=video_filename, sequence_length=sequence_length)\n",
    "        self.of_op = ops.OpticalFlow(device=\"gpu\", output_format=4)\n",
    "\n",
    "    def define_graph(self):\n",
    "        seq = self.input(name=\"Reader\")\n",
    "        of = self.of_op(seq.gpu())\n",
    "        return of"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Build and run DALI Pipeline."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 10, 180, 320, 2)\n"
     ]
    }
   ],
   "source": [
    "pipe = OFPipeline(batch_size=batch_size, num_threads=1, device_id=0)\n",
    "pipe.build()\n",
    "pipe_out = pipe.run()\n",
    "flow_vector = pipe_out[0].as_cpu().as_array()\n",
    "print(flow_vector.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Above you can see the shape of calculated `flow_vector` (in NFHWC format). It contains 2 channels: flow vector in `x` axis and flow vector in `y` axis. Output resolution is determined by `output_format` option passed to `OpticalFlow` operator: for `output_format = 4`, 4x4 grid is used for flow calculation, thus resolution in every dimension being 4 times smaller, than resolution of the input image.\n",
    "\n",
    "### Visualize results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f1a61fb4b70>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "of_result = flow_to_color(flow_vector[0][int(sequence_length/2)])\n",
    "plt.imshow(of_result)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
